#!/bin/sh

#
# Install a C build toolchain.
#
# suCGI is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# suCGI is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
# Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with suCGI. If not, see <https://www.gnu.org/licenses/>.
#

# shellcheck disable=2015,2086


#
# Initialiation
#

set -Ceu
scriptdir="$(cd -P "$(dirname -- "$0")" && pwd)"
: "${scriptdir:?}"
readonly scriptdir
# shellcheck disable=1091
. "$scriptdir/libutil.sh"	|| exit
init				|| exit


#
# Functions
#

hasall() (
	for __hasall_cmd
	do command -v "$__hasall_cmd" >/dev/null || return
	done
	return 0
)

hasany() (
	for __hasany_cmd
	do command -v "$__hasany_cmd" >/dev/null && return
	done
	return 1
)


#
# Constants
#

# File to log installed packages to.
# shellcheck disable=2154
logfile="$progname.log"


#
# Options
#

mode=install quiet=
OPTIND=1 OPTARG='' opt=''
while getopts hqr opt; do
	# shellcheck disable=2034
	case $opt in
	(h) exec cat <<EOF ;;
$progname - install a C build toolchain

Usage:  $progname [-q] [-r]
        $progname -h

Options:
    -r  Remove installed packages.
    -q  Be quiet.
    -h  Show this help screen.

Copyright 2023 Odin Kroeger.
Released under the GNU Affero General Public License.
This programme comes with ABSOLUTELY NO WARRANTY.
EOF
	(r) mode=remove ;;
	(q) quiet=y ;;
	(*) exit 2
	esac
done
shift $((OPTIND - 1))
unset opt

if [ $# -gt 0 ]
then
	printf 'usage: %s [-q] [-r]\n' "$progname" >&2
	exit 64
fi


#
# Main
#

os="$(uname)"

case $mode in
(install)
	hascomp='' hashdrs=''
	for cc in c99 gcc clang tcc cc
	do
		if command -v "$cc" >/dev/null
		then
			hascomp=y

			# shellcheck disable=2038
			sed -n -- '/^[ \t]*#[ \t]*include[ \t]*</p' *.c *.h |
			grep -Fve'<features.h>' -e'<sys/params.h>'          |
			sort -u                                             |
			"$cc" -E - >/dev/null 2>&1 && hashdrs=y

			break
		fi
	done

	missing=
	[ "$hascomp" ]			|| missing="$missing gcc"
	hasall ar as ld			|| missing="$missing binutils"
	hasany make gmake pmake	bsdmake	|| missing="$missing make"

	if ! [ "$missing" ] && [ "$hashdrs" ]
	then
		warn -q 'Complete build toolchain available; nothing to do'
		exit 0
	fi

	case $os in
	(Linux)
		if	[ -e /etc/alpine-release ]
		then
			[ "$hashdrs" ] ||
			missing="$missing libc-dev fortify-headers"

			printf '%s\n' $missing >"$logfile"
			exec apk add $missing

		elif	[ -e /etc/arch-release ]
		then
			exec pacman -S $missing

		elif	[ -e /etc/debian_version ] ||
			[ -e /etc/devuan_version ]
		then
			[ "$hashdrs" ] ||
			missing="$missing libc-dev"

			printf '%s\n' $missing >"$logfile"
			exec apt-get install $missing

		elif	[ -e /etc/fedora-release ]
		then
			[ "$hashdrs" ] ||
			missing="$missing glibc-devel"

			printf '%s\n' $missing >"$logfile"
			exec dnf install $missing
		fi
		;;
	esac

        warn 'Cannot auto-install build toolchain; please install:'

	inlist '=' gcc      $missing &&
	warn '* A C compiler (e.g., gcc or clang)'

	inlist '=' binutils $missing &&
	warn '* Binutils (i.e., ar, as, and ld)'

	inlist '=' make     $missing &&
	warn '* Make'

	[ "$hashdrs" ] ||
	warn "* The header files of your system's standard library"
	;;

(remove)
	[ -e "$logfile" ] ||
	err '%s: No such file' "$logfile"

	packages="$(cat "$logfile")" ||
	err '%s: Read error' "$logfile"

	[ "$packages" ] ||
	err 'No packages installed'

	case $os in
	(Linux)
		if	[ -e /etc/alpine-release ]
		then
			exec apk del $packages
		elif	[ -e /etc/arch-release ]
		then
			exec pacman -Rs $packages
		elif	[ -e /etc/debian_version ] ||
			[ -e /etc/devuan_version ]
		then
			exec apt-get remove --auto-remove --purge $packages
		elif	[ -e /etc/fedora-release ]
		then
			exec dnf remove $packages
		fi
		;;
	esac

	warn 'Package removal not supported on this system'
	warn 'You may want to remove: %s' "$packages"
	;;

(*)
	# NOTREACHED
	err 'line %s: Unknown mode' "${LINENO-???}"
esac

exit 1
